{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

import {Layout} from '@react-spectrum/docs';
export default Layout;

import docs from 'docs:@react-spectrum/picker';
import selectUtil from 'docs:@react-aria/test-utils/src/select.ts';
import {HeaderInfo, PropTable, PageDescription, ClassAPI, VersionBadge} from '@react-spectrum/docs';
import packageData from '@react-spectrum/picker/package.json';

```jsx import
import {Flex} from '@react-spectrum/layout';
import {Picker, Item, Section} from '@react-spectrum/picker';
import Book from '@spectrum-icons/workflow/Book';
import BulkEditUsers from '@spectrum-icons/workflow/BulkEditUsers';
import Draw from '@spectrum-icons/workflow/Draw';
import {Text} from '@react-spectrum/text';
import {Avatar} from "@react-spectrum/avatar";
```

---
category: Pickers
keywords: [select, collections, dropdown]
---

# Picker

<PageDescription>{docs.exports.Picker.description}</PageDescription>

<HeaderInfo
  packageData={packageData}
  componentNames={['Picker', 'Item', 'Section']}
  sourceData={[
    {type: 'Spectrum', url: 'https://spectrum.adobe.com/page/picker/'}
  ]}
  since="3.0.0" />

## Example
```tsx example
<Picker label="Choose frequency">
  <Item key="rarely">Rarely</Item>
  <Item key="sometimes">Sometimes</Item>
  <Item key="always">Always</Item>
</Picker>
```

## Content
Picker follows the [Collection Components](collections.html) API, accepting both static and dynamic collections. Similar to [Menu](Menu.html), Picker accepts `<Item>` elements as children, each with a `key` prop. Basic usage of Picker, seen in the example above, shows multiple options populated with a string. Static collections, as in this example, can be used when the full list of options is known ahead of time.

Dynamic collections, as shown below, can be used when the options come from an external data source such as an API call, or update over time. Providing the data in this way allows Picker to automatically cache the rendering of each item, which dramatically improves performance.

As seen below, an iterable list of options is passed to the Picker using the `items` prop. Each item accepts a key prop, which is passed to the `onSelectionChange` handler to identify the selected item. Alternatively, if the item objects contain an `id` property, as shown in the example below, then this is used automatically and a `key` prop is not required. See the [Events](#events) section for more detail on selection.

```tsx example
function Example() {
  let options = [
    {id: 1, name: 'Aardvark'},
    {id: 2, name: 'Cat'},
    {id: 3, name: 'Dog'},
    {id: 4, name: 'Kangaroo'},
    {id: 5, name: 'Koala'},
    {id: 6, name: 'Penguin'},
    {id: 7, name: 'Snake'},
    {id: 8, name: 'Turtle'},
    {id: 9, name: 'Wombat'}
  ];
  let [animalId, setAnimalId] = React.useState(null);

  return (
    <>
      <Picker label="Pick an animal" items={options} onSelectionChange={setAnimalId}>
        {item => <Item>{item.name}</Item>}
      </Picker>
      <p>Animal id: {animalId}</p>
    </>
  );
}
```

### Trays
On mobile, Pickers automatically display in a tray instead of a popover to improve usability.

### Internationalization
To internationalize a Picker, a localized string should be passed to the `children` of each `Item`.
For languages that are read right-to-left (e.g. Hebrew and Arabic), the layout of the Picker is automatically flipped.

## Labeling
Picker can be labeled using the `label` prop. If no label is provided, an alternative text label must be provided to identify the control for accessibility. This should be added using the `aria-label` prop. If the Picker is a required field, the `isRequired` and `necessityIndicator` props can be used to show a required state.

```tsx example
<Picker label="Choose frequency" isRequired necessityIndicator="icon">
  <Item key="rarely">Rarely</Item>
  <Item key="sometimes">Sometimes</Item>
  <Item key="always">Always</Item>
</Picker>
```
```tsx example
<Picker label="Choose frequency" isRequired necessityIndicator="label">
  <Item key="rarely">Rarely</Item>
  <Item key="sometimes">Sometimes</Item>
  <Item key="always">Always</Item>
</Picker>
```
```tsx example
<Picker label="Choose frequency" necessityIndicator="label">
  <Item key="rarely">Rarely</Item>
  <Item key="sometimes">Sometimes</Item>
  <Item key="always">Always</Item>
</Picker>
```

## Selection
Setting a selected option can be done by using the `defaultSelectedKey` or `selectedKey` prop. The selected key corresponds to the `key` of an item. See [Events](#events) for more details on selection events.
Additionally see the `react-stately` [Selection docs](selection.html#selected-key-data-type) for caveats regarding selection prop typing.

```tsx example
import type {Key} from '@adobe/react-spectrum';

function Example() {
  let options = [
    {name: 'Koala'},
    {name: 'Kangaroo'},
    {name: 'Platypus'},
    {name: 'Bald Eagle'},
    {name: 'Bison'},
    {name: 'Skunk'}
  ];
  let [animal, setAnimal] = React.useState<Key>("Bison");

  return (
    <Flex gap="size-150" wrap>
      <Picker
        label="Pick an animal (uncontrolled)"
        items={options}
        defaultSelectedKey="Bison">
        {item => <Item key={item.name}>{item.name}</Item>}
      </Picker>

      <Picker
        label="Pick an animal (controlled)"
        items={options}
        selectedKey={animal}
        onSelectionChange={selected => setAnimal(selected)}>
        {item => <Item key={item.name}>{item.name}</Item>}
      </Picker>
    </Flex>
  );
}
```

### HTML forms

Picker supports the `name` prop for integration with HTML forms. The `key` of the selected item will be submitted to the server.

```tsx example
<Picker
  label="Favorite Animal"
  ///- begin highlight -///
  name="favoriteAnimalId"
  ///- end highlight -///
>
  <Item key="panda">Panda</Item>
  <Item key="cat">Cat</Item>
  <Item key="dog">Dog</Item>
</Picker>
```

## Links

By default, interacting with an item in a Picker triggers `onSelectionChange`. Alternatively, items may be links to another page or website. This can be achieved by passing the `href` prop to the `<Item>` component. Link items in a `Picker` are not selectable.

```tsx example
<Picker label="Project">
  <Item href="https://example.com/" target="_blank">Create new…</Item>
  <Item>Proposal</Item>
  <Item>Budget</Item>
  <Item>Onboarding</Item>
</Picker>
```

### Client side routing

The `<Item>` component works with frameworks and client side routers like [Next.js](https://nextjs.org/) and [React Router](https://reactrouter.com/en/main). As with other React Spectrum components that support links, this works via the [Provider](Provider.html) component at the root of your app. See the [client side routing guide](routing.html) to learn how to set this up.

## Sections
Picker supports sections in order to group options. Sections can be used by wrapping groups of items in a `Section` element. Each `Section` takes a `title` and `key` prop.

### Static items
```tsx example
<Picker label="Pick your favorite">
  <Section title="Animals">
    <Item key="Aardvark">Aardvark</Item>
    <Item key="Kangaroo">Kangaroo</Item>
    <Item key="Snake">Snake</Item>
  </Section>
  <Section title="People">
    <Item key="Danni">Danni</Item>
    <Item key="Devon">Devon</Item>
    <Item key="Ross">Ross</Item>
  </Section>
</Picker>
```
### Dynamic items
Sections used with dynamic items are populated from a hierarchical data structure. Similarly to the props on `Picker`, `Section` takes an array of data using the `items` prop.

```tsx example
function Example() {
  let options = [
    {name: 'Australian', children: [
      {id: 2, name: 'Koala'},
      {id: 3, name: 'Kangaroo'},
      {id: 4, name: 'Platypus'}
    ]},
    {name: 'American', children: [
      {id: 6, name: 'Bald Eagle'},
      {id: 7, name: 'Bison'},
      {id: 8, name: 'Skunk'}
    ]}
  ];

  return (
    <Picker label="Pick an animal" items={options} onSelectionChange={selected => alert(selected)}>
      {item => (
        <Section key={item.name} items={item.children} title={item.name}>
          {item => <Item>{item.name}</Item>}
        </Section>
      )}
    </Picker>
  );
}
```

## Events
Picker supports selection via mouse, keyboard, and touch. You can handle all of these via the `onSelectionChange`
prop. Picker will pass the selected `key` to the `onSelectionChange` handler.

The following example uses an `onSelectionChange` handler to update the selection stored in React state.

```tsx example
function StaticExample() {
  let [frequency, setFrequency] = React.useState(null);

  return (
    <>
      <Picker label="Choose frequency" onSelectionChange={selected => setFrequency(selected)}>
        <Item key="Rarely">Rarely</Item>
        <Item key="Sometimes">Sometimes</Item>
        <Item key="Always">Always</Item>
      </Picker>
      <p>You selected {frequency}</p>
    </>
  );
}
```

When using Picker with dynamic items, selection works much the same way using `key`. However, if your data already has an `id` property (as is common with many data sets), Picker can use that id without needing to specify a `key` prop. The below example shows Picker using the id of each item from the `items` array as the selected value without the need for `key`. Note that `key` will always take precedence if set.

```tsx example
function DynamicExample() {
  let [animalId, setAnimalId] = React.useState(null);
  let options = [
    {id: 1, name: 'Aardvark'},
    {id: 2, name: 'Cat'},
    {id: 3, name: 'Dog'},
    {id: 4, name: 'Kangaroo'},
    {id: 5, name: 'Koala'},
    {id: 6, name: 'Penguin'},
    {id: 7, name: 'Snake'},
    {id: 8, name: 'Turtle'},
    {id: 9, name: 'Wombat'}
  ];

  return (
    <>
      <Picker label="Pick an animal" items={options} onSelectionChange={selected => setAnimalId(selected)}>
        {item => <Item>{item.name}</Item>}
      </Picker>
      <p>Your favorite animal has id: {animalId}</p>
    </>
  );
}
```

## Complex items
Items within Picker also allow for additional content used to better communicate options. Icons, avatars, and descriptions can be added to the `children` of `Item` as shown in the example below.
If a description is added, the prop `slot="description"` must be used to distinguish the different `<Text>` elements.
See Icon's [labeling](workflow-icons.html#labeling) section and Avatar's [accessibility](Avatar.html#accessibility) section for more information on how to label these elements.

```tsx example
<Picker label="Options">
  <Section title="Permission">
    <Item textValue="Read">
      <Book size="S" />
      <Text>Read</Text>
      <Text slot="description">Read Only</Text>
    </Item>
    <Item textValue="Write">
      <Draw size="S" />
      <Text>Write</Text>
      <Text slot="description">Read and Write Only</Text>
    </Item>
    <Item textValue="Admin">
      <BulkEditUsers size="S" />
      <Text>Admin</Text>
      <Text slot="description">Full access</Text>
    </Item>
  </Section>
</Picker>
```

### With avatars

```tsx example
<Picker label="Select a user">
  <Item textValue="User 1">
    <Avatar src="https://i.imgur.com/kJOwAdv.png" />
    <Text>User 1</Text>
  </Item>
  <Item textValue="User 2">
    <Avatar src="https://i.imgur.com/kJOwAdv.png" />
    <Text>User 2</Text>
  </Item>
  <Item textValue="User 3">
    <Avatar src="https://i.imgur.com/kJOwAdv.png" />
    <Text>User 3</Text>
  </Item>
  <Item textValue="User 4">
    <Avatar src="https://i.imgur.com/kJOwAdv.png" />
    <Text>User 4</Text>
  </Item>
</Picker>
```

## Asynchronous loading

Picker supports loading data asynchronously, and will display a progress circle when the `isLoading` prop is set.
It also supports infinite scrolling to load more data on demand as the user scrolls, via the `onLoadMore` prop.

This example uses the [useAsyncList](react-aria:useAsyncList.html) hook to handle loading the data.
See the docs for more information.

```tsx example
import {useAsyncList} from '@react-stately/data';

interface Pokemon {
  name: string
}

function AsyncLoadingExample() {
  let list = useAsyncList<Pokemon>({
    async load({signal, cursor}) {
      // If no cursor is available, then we're loading the first page.
      // Otherwise, the cursor is the next URL to load, as returned from the previous page.
      let res = await fetch(cursor || 'https://pokeapi.co/api/v2/pokemon', {signal});
      let json = await res.json();
      return {
        items: json.results,
        cursor: json.next
      };
    }
  });

  return (
    <Picker
      label="Pick a Pokemon"
      items={list.items}
      isLoading={list.isLoading}
      onLoadMore={list.loadMore}>
      {item => <Item key={item.name}>{item.name}</Item>}
    </Picker>
  );
}
```

## Validation

Picker supports the `isRequired` prop to ensure the user selects an option, as well as custom client and server-side validation. It can also be integrated with other form libraries. See the [Forms](forms.html) guide to learn more.

When the [Form](Form.html) component has the `validationBehavior="native"` prop, validation errors block form submission and are displayed as help text automatically.

```tsx example
import {Form, ButtonGroup, Button} from '@adobe/react-spectrum';

<Form validationBehavior="native" maxWidth="size-3000">
  {/*- begin highlight -*/}
  <Picker label="Favorite animal" name="animal" isRequired>
  {/*- end highlight -*/}
    <Item>Aardvark</Item>
    <Item>Cat</Item>
    <Item>Dog</Item>
    <Item>Kangaroo</Item>
    <Item>Panda</Item>
    <Item>Snake</Item>
  </Picker>
  <ButtonGroup>
    <Button type="submit" variant="primary">Submit</Button>
    <Button type="reset" variant="secondary">Reset</Button>
  </ButtonGroup>
</Form>
```

By default, `Picker` displays default validation messages provided by the browser. See [Customizing error messages](forms.html#customizing-error-messages) in the Forms guide to learn how to provide your own custom errors.

## Props

<PropTable component={docs.exports.Picker} links={docs.links} />

## Visual options

### Label alignment and position

By default, the label is positioned above the Picker. The `labelPosition` prop can be used to position the label to the side. The `labelAlign` prop can be used to align the label as "start" or "end". For left-to-right (LTR) languages, "start" refers to the left most edge of the Picker and "end" refers to the right most edge. For right-to-left (RTL) languages, this is flipped.

```tsx example
<Picker label="Choose frequency" labelPosition="side" labelAlign="end">
  <Item key="rarely">Rarely</Item>
  <Item key="sometimes">Sometimes</Item>
  <Item key="always">Always</Item>
</Picker>
```
### Quiet
```tsx example
<Picker label="Choose frequency" isQuiet>
  <Item key="rarely">Rarely</Item>
  <Item key="sometimes">Sometimes</Item>
  <Item key="always">Always</Item>
</Picker>
```
### Disabled
```tsx example
<Picker label="Choose frequency" isDisabled>
  <Item key="rarely">Rarely</Item>
  <Item key="sometimes">Sometimes</Item>
  <Item key="always">Always</Item>
</Picker>
```

### Help text
[View guidelines](https://spectrum.adobe.com/page/picker/#Help-text-(description-and-error-message))

Both a description and an error message can be supplied to a Picker. The description is always visible unless `isInvalid` is true and an error message is provided. The error message can be used to help the user fix their input quickly and should be specific to the detected error. All strings should be localized.

```tsx example
function Example() {
    let [animalId, setAnimalId] = React.useState(null);
    let options = [
      {id: 1, name: 'Aardvark'},
      {id: 2, name: 'Cat'},
      {id: 3, name: 'Dog'},
      {id: 4, name: 'Kangaroo'},
      {id: 5, name: 'Koala'},
      {id: 6, name: 'Penguin'},
      {id: 7, name: 'Snake'},
      {id: 8, name: 'Turtle'},
      {id: 9, name: 'Wombat'}
    ];
  let isValid = React.useMemo(() => animalId !== 2 && animalId !== 7, [animalId]);

  return (
    <Picker
      isInvalid={!isValid}
      label="Favorite animal"
      description="Pick your favorite animal, you will be judged."
      errorMessage={animalId === 2 ? 'The author of this example is a dog person.' : 'Oh no it\'s a snake! Choose anything else.'}
      items={options}
      selectedKey={animalId}
      onSelectionChange={selected => setAnimalId(selected)}>
      {item => <Item>{item.name}</Item>}
    </Picker>
  );
}
```

### Contextual help

A [ContextualHelp](ContextualHelp.html) element may be placed next to the label to provide additional information or help about a Picker.

```tsx example
import {Content, ContextualHelp, Heading} from '@adobe/react-spectrum';

<Picker
  label="Engineering major"
  contextualHelp={
    <ContextualHelp variant="info">
      <Heading>Major changes</Heading>
      <Content>Once you have changed your major, you cannot change it back.</Content>
    </ContextualHelp>
  }>
  <Item>Aerospace</Item>
  <Item>Mechanical</Item>
  <Item>Civil</Item>
  <Item>Nuclear</Item>
  <Item>Industrial</Item>
  <Item>Chemical</Item>
  <Item>Agricultural</Item>
  <Item>Electrical</Item>
</Picker>
```

### Custom widths
```tsx example
<Flex direction="column" rowGap="size-150">
  <Picker label="Choose frequency" width="size-3600" maxWidth="100%">
    <Item key="rarely">Rarely</Item>
    <Item key="sometimes">Sometimes</Item>
    <Item key="always">Always</Item>
  </Picker>

  <Picker label="Choose animal" menuWidth="size-6000">
    <Item key="Emu">Emu</Item>
    <Item key="Kangaroo">Kangaroo</Item>
    <Item key="Platypus">Platypus</Item>
  </Picker>
</Flex>
```

### Align and direction
```tsx example
<Flex direction="column" gap="size-150">
  <Picker label="Choose frequency" align="end" menuWidth="size-3000">
    <Item key="rarely">Rarely</Item>
    <Item key="sometimes">Sometimes</Item>
    <Item key="always">Always</Item>
  </Picker>

  <Picker label="Choose animal" direction="top">
    <Item key="Emu">Emu</Item>
    <Item key="Kangaroo">Kangaroo</Item>
    <Item key="Platypus">Platypus</Item>
  </Picker>
</Flex>
```

### Menu state
The open state of the menu can be controlled via the `defaultOpen` and `isOpen` props

```tsx example
function Example() {
  let [open, setOpen] = React.useState(false);

  return (
    <Picker
      label="Frequency"
      isOpen={open}
      onOpenChange={setOpen}>
      <Item key="rarely">Rarely</Item>
      <Item key="sometimes">Sometimes</Item>
      <Item key="always">Always</Item>
    </Picker>
  );
}
```

## Testing

The Picker features an overlay that transitions in and out of the page as it is opened and closed. Depending on
your device configuration, this overlay may render as a tray or a dropdown. Additionally, the Picker features automatic virtualization
and may need specific mocks in a test environment to enable said virtualization properly. Please see the following sections in the testing docs
for more information on how to handle these behaviors in your test suite.

[Timers](./testing.html#timers)

[Desktop vs Mobile](./testing.html#desktop-vs-mobile)

[Virtualized Components](./testing.html#virtualized-components)

[Long press](./testing.html#simulating-user-long-press)

Please also refer to [React Spectrum's test suite](https://github.com/adobe/react-spectrum/blob/main/packages/%40react-spectrum/picker/test/Picker.test.js) if you find that the above
isn't sufficient when resolving issues in your own test cases.

### Test utils <VersionBadge version="beta" style={{marginLeft: 4, verticalAlign: 'bottom'}} />

`@react-spectrum/test-utils` offers common select interaction utilities which you may find helpful when writing tests. See [here](./testing.html#react-spectrum-test-utils) for more information on how to setup these utilities
in your tests. Below is the full definition of the select tester and a sample of how you could use it in your test suite.

```ts
// Picker.test.ts
import {render} from '@testing-library/react';
import {theme} from '@react-spectrum/theme-default';
import {User} from '@react-spectrum/test-utils';

let testUtilUser = new User({interactionType: 'mouse'});
// Other setup, be sure to check out the suggested mocks mentioned above in https://react-spectrum.adobe.com/react-spectrum/Picker.html#testing

it('Picker can select an option via keyboard', async function () {
  // Render your test component/app and initialize the select tester
  let {getByTestId} = render(
    <Provider theme={defaultTheme}>
      <Picker data-testid="test-select">
      ...
      </Picker>
    </Provider>
  );
  let selectTester = testUtilUser.createTester('Select', {root: getByTestId('test-select'), interactionType: 'keyboard'});
  let trigger = selectTester.trigger;
  expect(trigger).toHaveTextContent('Select…');

  await selectTester.selectOption({option: 'Cat'});
  expect(trigger).toHaveTextContent('Cat');
});
```

<ClassAPI links={selectUtil.links} class={selectUtil.exports.SelectTester} />
